package ipcards;

import ipcards.events.*;
import ipcards.net.Client;

import java.util.*;

/**
 * Models a Player
 */
public class Player implements PlayerActionPerformer, Comparable<Player> {
	
	private ArrayList<PlayerActionListener> listeners = new ArrayList<PlayerActionListener>();
	
	public Room room;
	public String name;
	
	public Vector<Card> recievedCards = new Vector<Card>();
	public CardSet selectedCards = new CardSet();
	public CardSet heldCards = new CardSet(); // cards controlled by selector
	public CardSet locallyFlippedCards = new CardSet();
	public Client thisclient;
	
	
	public Player(String _name) {
		name = _name;
	}
		
	public void setClient(Client c) {
		thisclient = c;
	}
	
	public void setRoom(Room r) {
		room = r;
	}
	
	public void addPlayerActionListener(PlayerActionListener listener) {
		listeners.add(listener);
	}
	
	public void playerActionPerformed(PlayerAction pa) {
		for(PlayerActionListener l: listeners) {
			l.playerActionPerformed(pa);
		}
	}
	
	
	/**
	 * Tests if a {@link Card} is currently selected.
	 * @param card The <code>Card</code> to test.
	 * @return <code>true</code> if the specified <code>Card</code> is selected, otherwise <code>false</code>.
	 */
	public boolean isSelectedCard(Card card) {
		return selectedCards.contains(card);
	}
	
	public boolean isSelected() {
		return !selectedCards.isEmpty();
	}
	
	public int getNumberOfCards() {
		return selectedCards.size();
	}
	
	public boolean isLocallyFlipped(Card c) {
		return locallyFlippedCards.contains(c);
	}

	
	/**
	 * Called when a PlayerAction is fired. 
	 * Receives PlayerActions from the GUI and the server Connection.
	 */
	public void performPlayerAction(PlayerAction pa) {
		CardSet cardsToChange;
		boolean changeGUI = true;
		
		if (pa.getCards() == null)
			cardsToChange = new CardSet(selectedCards);
		else
			cardsToChange = pa.getCards();

		switch (pa.getAction()) {
		
		case PlayerAction.SELECTION_ADD:
			selectedCards.addAll(cardsToChange);
			break;
			
		case PlayerAction.SELECTION_REMOVE:
			for (Card c: cardsToChange)
				selectedCards.remove(c);
			break;
			
		case PlayerAction.HOLD:
			heldCards.addAll(cardsToChange);
			break;
			
		case PlayerAction.RELEASE:
			for (Card c: cardsToChange)
				heldCards.remove(c);
			break;
			
		case PlayerAction.MOVE:
			for(Card c: cardsToChange)
				c.moveBy(pa.getChange());
			break;
			
		case PlayerAction.FLIP:
			for(Card c: cardsToChange)
				c.toggleFaceUp();
			break;
			
		case PlayerAction.LOCAL_FLIP:
			boolean isFlipped = true;
			
			//Always locally flip all cards, unless all selected cards are flipped allready
			for(Card c: cardsToChange) {
				if (!locallyFlippedCards.contains(c))
					isFlipped = false;
			}

			for(Card c: cardsToChange) {
				if(isFlipped)
					locallyFlippedCards.remove(c);
				else
					locallyFlippedCards.add(c);
			}			
			
			break;	
			
		case PlayerAction.SHUFFLE:
			break;
			
		case PlayerAction.NEW_GAME:
			if(pa.getArgs().charAt(0) == PlayerAction.SHOW_DIALOG){
				changeGUI = false;
				room.controller.view.newGameExternal(pa.getArgs().substring(3));
			}
			else if(pa.getArgs().charAt(0) == PlayerAction.NEW_GAME){		//new game request has been denied
				changeGUI = false;
				room.controller.view.newGameDenied();
			}
			else{
				String args = pa.getArgs();
				String[] args2 = args.split("::");
				int extraDecks = Integer.parseInt(args2[0]);
				room.table.newGame(args2[1], null, extraDecks);
//System.out.println("13847510374aljfhvalrdhgfljahgbaljkrfhgbaljrfhgblajdfhgbalshrgfajlrhdfgblajerhgflajwrhgfbalrhbaldblaidhfba,lfsdjshzjlshbglgaerhwglauerhgblakugflaierygfladbhvglajhgfbliaurgliaerugliaurglisaerugp;aeirughpreiuliqerughailuergflauergfbaljrsdhfgblajrgblaeruihgalierhglaserhghlsaueirgaleiurghaieulrgalierhfbglaifdgbkjasrbgflakjdbhglaerhgblaierygbaluierygaiulesgr");				

			}
			break;
		
		case PlayerAction.ADD_DECK:
			room.table.addDeck(new Deck(pa.getArgs()));
			break;
		
		case PlayerAction.SYNC_LOCATIONS:
			String[] cards = pa.getArgs().split(PlayerAction.DEL);
			int pos = 0;
			int z = 0;
			
			CardSet deck = room.table.cards;
			Card tempCard;
			LinkedList<Card> drawingList = room.table.drawingList;
			drawingList.clear();
			
			while(pos < cards.length) {
				tempCard = deck.getCardFromID(Integer.parseInt(cards[pos++]));
				tempCard.setLocation(Integer.parseInt(cards[pos++]), Integer.parseInt(cards[pos++]));
				tempCard.setFaceUp(cards[pos++].equals("1") ? true : false);
				tempCard.setZ(z++);
				drawingList.add(tempCard);
			}
		break;
		
		case PlayerAction.SET_FACE_UP:
			for(Card c: cardsToChange) {
				c.setFaceUp();
			}
			break;
			
		case PlayerAction.SET_FACE_DOWN:
			for(Card c: cardsToChange)
				c.setFaceDown();
			break;
		
		case PlayerAction.RESET_LOCAL_FLIP:
			for(Card c: cardsToChange) {
				locallyFlippedCards.remove(c);
			}
			break;	
			
		case PlayerAction.SEND_NAME_HASHMAP:
			String args = pa.getArgs().trim();
			String[] splitargs = args.split(":");
			for(int i=0; i<splitargs.length - 1; i+=2){
				int key = Integer.parseInt(splitargs[i]);
				String name = splitargs[i+1];
				room.table.allPlayers.put(key, name);
			}
			break;
						
		}
		
		if(changeGUI){
			this.playerActionPerformed(pa);
		}
		changeGUI = true;
	}
	
	public int compareTo(Player player) {
		if(player.thisclient == null && thisclient == null) {			//comparing the table with itself
			return 0;
		}
		else if(player.thisclient == null && !(thisclient == null)) {	//comparing the table with another player
			return 10;
		}
		else if(!(player.thisclient == null) && thisclient == null) {	//comparing another player with the table 
			return -10;
		}
		else {																		//comparing one player with another
			return (player.thisclient.getSocket().hashCode()) - (thisclient.getSocket().hashCode());
		}
	}
}













